<template>
  <div class="chat-container">
    <div class="bar">
      <img src="@/assets/search/bz8.svg" style="cursor: pointer;" alt="" @click.native='activeWeb' />
      <div class="right">
        <el-tooltip v-for="(item, index) in btnList" :key="item.name" class="box-item" effect="dark" :content="item.name">
          <el-popconfirm v-if="item.name === '清空'" :width="200" hide-icon title="聊天记录不可恢复。确定清空？" confirm-button-text="确定" cancel-button-text="取消" @confirm="confirmEvent"
            @cancel="cancelEvent">
            <template #reference>
              <img class="box-img" :src="item.src" alt="" />
            </template>
          </el-popconfirm>
          <img v-else class="box-img" :src="item.src" alt="" @click.native='btnClick(item.name)' />
        </el-tooltip>
        <ClosePop type="chat"></ClosePop>
      </div>
    </div>
    <ul class="chat-list" ref="chatContainer" v-notDrag>
      <template v-for="item in chatList" :key="item.id">
        <li class="right-chat" v-if="item.type === 'question'">
          <div style="overflow: hidden">
            <div class="chat" v-notDrag>
              <div class="operate">
                <el-tooltip v-if="!isCopy" class="box-item" effect="dark" content="复制到输入框">
                  <div class="iconfont_Con">
                    <span class="iconfont" @click="copyQuestion(item)">&#xe8b0;</span>
                  </div>
                </el-tooltip>
                <span v-else style="color: greenyellow; font-size: 20px">√</span>
              </div>
              <span v-if="'propmpt' in item && Object.keys(item.propmpt as object).length > 0" class="propmpt"
                :style="{ ...item.propmpt?.style }">
                <div style="display: inline-block;">{{ item.propmpt?.text }}</div>
              </span>
              <span class="text">{{ item.text }}</span>
            </div>
          </div>
        </li>
        <li class="left-chat" v-else>
          <div class="chat" v-notDrag>
            <div class="operate">
              <span v-if="!isCopy" class="iconfont" @click="copyContent(item.text)">&#xe8b0;</span>
              <span v-else style="color: greenyellow; font-size: 20px">√</span>
            </div>
            <span class="text">{{ item.text }}</span>
          </div>
          <div></div>
        </li>
      </template>
      <li v-show="isSending">
        <div @click.native='stopChat' class="stopChatBtn">
          <img src="@/assets/search/stopChat.svg" class="stopChatImg" alt="" />
          <div>停止回答</div>
        </div>
      </li>
    </ul>

  </div>
</template>

<script lang="ts">
import Base64 from 'base-64';
import utf8 from 'utf8';
import { defineComponent, PropType, ref, computed, nextTick, watch } from "vue";
import { isElectron } from "@/utils";
import { useRouter } from "vue-router";

import { chatItem, chatType, SendMessage } from "./types";
import { useEditChatContent } from "./editChatContent";
import { useCopyContent } from "./copyContent";
import { generateRandomChars } from "@/utils";
import { chatTestUrl, clearConversation } from "@/utils/api.ts";
import { Propmpt } from "../../../types";
import ClosePop from "./closePop.vue"

import img2 from '@/assets/search/bz2.svg';
import img10 from '@/assets/search/bz10.svg';
import img11 from '@/assets/search/bz11.svg';
import img12 from '@/assets/search/bz12.svg';
import zoominImg from '@/assets/search/zoommin.svg';

const router = useRouter();
export default defineComponent({
  name: "",
  components: {
    ClosePop
  },
  props: {
    close: {
      type: Function,
    },
    sendMessage: {
      type: Object as PropType<SendMessage>,
    },
    isSending: {
      type: Boolean
    }
  },
  setup(props, ctx) {
    const btnList = ref([
      { name: '置顶', src: img10 },
      { name: '清空', src: img11 },
      { name: '设置', src: img12 },
      { name: '最小化', src: zoominImg },
      { name: '折叠', src: img2 },
    ]);
    const isSendingRef = computed(() => props.isSending);
    let propmpts = ref(
      JSON.parse(localStorage.getItem("propmpts") || "null") || []
    );
    const userInfo = JSON.parse(localStorage.getItem("userInfo") || "null");
    const currParam = {
      "userId": userInfo.user_id,
      "category": userInfo.category,
      "kind": userInfo.kind,
      "conv_id": userInfo.convId,
      "convId": userInfo.convId,
      prompt: '',
      "stream": "1"
    }

    function getHistoryInfo(questionText: string) {
      let str = questionText;
      let placholder: any = null;
      let propmpt = {};
      if (questionText && questionText.includes('\n\n\n```')) {
        const placholderList = questionText.match(/(\S*)\n\n\n```/);
        if (placholderList && placholderList.length > 1) {
          placholder = placholderList[1]
        } else {
          placholder = ''
        }
        const strList = questionText.match(/\n\n\n```(\S*)```\n\n\n/);
        if (strList && strList.length > 1) {
          str = strList[1]
        } else {
          str = ''
        }
        console.log(propmpt)
      }
      if (placholder) {
        propmpt = propmpts.value.find((value: any) => value.placholder === placholder)
        if (!propmpt) propmpt = {}
      }

      const Qtext = str ? str : questionText;
      return { Qtext, propmpt }
    }

    let historyList = userInfo.messages.map((item: any, index: any) => {
      const { Qtext, propmpt } = getHistoryInfo(baseDecode(item.Q))
      return [{
        id: index + "q",
        type: "question",
        text: Qtext,
        propmpt,
        visible: false,
      }, {
        id: index + "s",
        type: "answer",
        text: baseDecode(item.A),
        visible: false,
      }]
    })

    historyList = historyList.flat(2);
    console.log(historyList);
    const chatList = ref(historyList || []);//computed(() => props.chatList);

    const { copyContent, isCopy } = useCopyContent();
    const { preEdit, confirmEdit, curText } = useEditChatContent();
    const chatContainer = ref<HTMLElement>();

    const copyQuestion = (opt: any) => {
      ctx.emit('copyQuestion', opt);
    }

    function onTop() {
      if (!isElectron()) return
      const { ipcRenderer } = require("electron");
      ipcRenderer.invoke("onTop");
    }

    const confirmEvent = async () => {
      const userInfo = JSON.parse(localStorage.getItem("userInfo") || "null");
      const currParam = {
        "category": userInfo.category,
        "kind": userInfo.kind,
        "convId": userInfo.convId,
      }
      const info = await clearConversation(currParam);
      if (info.msg === 'success') {
        userInfo.convId = info.data.convId;
        localStorage.setItem("userInfo", JSON.stringify(userInfo) || '');
        ctx.emit('clearChat')
      }
    }
    const cancelEvent = () => {
      console.log('cancel!')
    }

    function btnClick(name: any) {
      if (name === '置顶') onTop();
      if (name === '清空') ctx.emit('clearChat');
      if (name === '折叠') closeChat();
      if (name === '设置') setting();
      if (name === '最小化') ctx.emit("miniSize");
    }

    const onClear = () => {
      chatList.value = []
    }

    function setting() {
      ctx.emit('setting');
    }

    function* generateAnswer() {
      for (let i = 0; i < 20; i++) {
        const randomChars: string = generateRandomChars(10);
        yield randomChars;
      }
    }
    let gen: any;

    function baseDecode(str: string) {
      return decodeURIComponent(
        atob(str)
          .split('')
          .map(function (c) {
            return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
          })
          .join(''),
      );
    }

    function getPromptCode(content: any, inputValue: any) {
      let prompts = Base64.encode(utf8.encode(inputValue.trim()));
      if (content && content !== '') {
        prompts = Base64.encode(
          utf8.encode(content + '\n\n\n```' + inputValue.trim() + '```\n\n\n'),
        );
      } else {
        prompts = Base64.encode(utf8.encode(inputValue.trim()));
      }
      return prompts
    }

    function stopChat() {
      ctx.emit("setSending", false);
    }

    watch(
      () => props.sendMessage,
      async () => {
        console.log(props?.isSending);
        if (props?.isSending) return;
        gen = generateAnswer();
        let propmpt = props.sendMessage?.propmpt;
        console.log('changed')
        let selectedText = props.sendMessage?.text || "";
        if (propmpt && selectedText.trim().length > 0) {
          console.log(propmpt, selectedText.trim())
          await addChat(true, "question", selectedText, propmpt);
          await addChat(true, "answer", "", undefined);

          currParam.prompt = getPromptCode(propmpt.placholder || '', selectedText.trim())
          const userInfo = JSON.parse(localStorage.getItem("userInfo") || "null");
          currParam.convId = userInfo.convId;
          currParam.conv_id = userInfo.convId;
          currParam.modelName = "闭源GPT-16k"

          try {
            const response: any = await fetch(
              `${chatTestUrl}/dwgpt/chatpage/chat`,
              {
                method: 'POST',
                body: JSON.stringify(currParam),
                headers: {
                  'Content-Type': 'application/json',
                },
              },
            );

            const encode = new TextDecoder('utf-8');
            const reader = response.body.getReader();

            const { done, value } = await reader.read();

            const firstText = encode.decode(value);
            if (firstText.includes(`"code": "205"`)) {
              const errorJson = JSON.parse(firstText);//判断是否是205未登录状态
              console.log(errorJson.code, errorJson.message)
              // 判断
              if (isElectron()) {
                const { ipcRenderer } = require("electron");
                await ipcRenderer.invoke("isLogout");
              } else {
                router.push("/login");
              }
              return
            }

            await addChat(false, "answer", firstText as string, propmpt);
            ctx.emit("setSending", true);
            while (true) {
              const { done, value } = await reader.read();
              
              const text = encode.decode(value);
              console.log(text)
              if (text.includes('[DONE]')) {
                ctx.emit("setSending", false);
                break;
              } else if (text === '<ERR>') {
                ctx.emit("setSending", false);
                break;
              } else {
                await addChat(false, "answer", text as string, propmpt);
              }
              if (done) {
                ctx.emit("setSending", false);
                break;
              }
              if (!isSendingRef.value) {
                break;
              }
            }
          } catch (e) {
            console.log(e)
          }
        }
      }
    );
    function addChat(
      flag: boolean,
      type: chatType = "question",
      text: string,
      propmpt?: Propmpt,
    ) {
      return new Promise((resolve) => {
        let chatItem: chatItem = {
          id: chatList.value.length.toString(),
          type,
          text,
          propmpt,
          visible: false,
        };
        if (flag) {
          console.log(chatItem)
          chatList.value.push(chatItem);
        } else {
          let answerText = chatList.value[chatList.value.length - 1].text;
          answerText += text;
          chatList.value[chatList.value.length - 1].text = answerText;
        }
        nextTick(() => {
          if (chatContainer.value) {
            chatContainer.value.scrollTop = chatContainer.value?.scrollHeight;
            resolve(true);
          }
        });
      });
    }
    function closeChat() {
      ctx.emit("close", false);
    }

    function activeWeb() {
      ctx.emit('activeWeb')
    }


    return {
      stopChat,
      onClear,
      btnClick,
      btnList,
      chatList,
      closeChat,
      chatContainer,
      preEdit,
      confirmEdit,
      curText,
      copyContent,
      copyQuestion,
      isCopy,
      activeWeb,
      confirmEvent,
      cancelEvent,
    };
  },
});
</script>
<style scoped lang="scss">
.chat-container {
  width: 100%;
  height: 440px;
  position: relative;
  padding-top: 20px;
  background: #f3f5fd;
  border-top-left-radius: 20px;
  border-top-right-radius: 20px;
  box-sizing: border-box;

  .bar {
    padding: 0 20px;
    display: flex;
    justify-content: space-between;
  }

  .right {
    display: flex;
    align-items: start;
  }

  .box-img {
    width: 20px;
    height:20px;
    margin-left: 16px;
    cursor: pointer;
  }

  .close {
    position: absolute;
    right: 10px;
    top: 10px;
    cursor: pointer;
  }

  .propmpt {
    border-radius: 10px;
    padding: 3px 10px;
    margin-right: 6px;
    background: #E2EBFF;
    border-radius: 4px;
    font-size: 14px;
    font-family: PingFangSC-Semibold, PingFang SC;
    // font-weight: 600;
    color: #3E83F6;
  }
}

.chat-list li {
  position: relative;
  list-style-type: none;
  z-index: 2;
}

.chat-list {
  position: relative;
  padding-top: 20px;
  -ms-overflow-style: none;
  scrollbar-width: none;
  overflow-y: auto;
  overflow-x: hidden;
  height: 360px;
}

.chat-list::-webkit-scrollbar {
  // display: none;
  /* Chrome Safari */
}

::-webkit-scrollbar {
  width: 7px;
  height: 10px;
}

::-webkit-scrollbar-thumb {
  background: #D8D8D8;
  border-radius: 4px;
}

.chat {
  padding: 15px;
  margin: 0 10px;
  position: relative;
  border-radius: 4px;
  word-break: break-all;
  white-space: pre-wrap;
  display: inline-block;
  max-width: 400px;
}

.stopChatBtn {
  width: 80px;
  margin-left: 20px;//160px;
  display: flex;
  justify-content: center;
  color: #2567F0;
  font-weight: 500;
  background-color: rgba(37, 103, 240, 0.1);
  padding: 10px 20px;
  border-radius: 20px;
  cursor: pointer;

  .stopChatImg {
    width: 14px;
    height: 14px;
    margin-top: 2px;
    margin-right: 8px;
  }
}

.iconfont_Con {
  padding: 4px 6px;
  background: #FFFFFF;
  box-shadow: 0px 0px 7px 1px rgba(188, 188, 188, 0.5);
  border-radius: 10px;
}

.right-chat {
  .iconfont {
    color: #333333
  }

  .iconfont:hover {
    color: #4C91F9
  }

  .operate {
    position: absolute;
    // right: 440px;
    margin-left: -60px;
    top: 50%;
    transform: translateY(-50%);
    opacity: 0;
    transition: opacity 0.3s;

    span {
      font-size: 18px;
      cursor: pointer;
    }
  }

  &:hover .operate {
    opacity: 1;
  }
}

.left-chat {
  .operate {
    position: absolute;
    left: 420px;
    top: 50%;
    transform: translateY(-50%);
    opacity: 0;
    transition: opacity 0.3s;

    span {
      margin-left: 20px;
      font-size: 24px;
      cursor: pointer;
    }
  }

  &:hover .operate {
    opacity: 1;
  }

  .text {
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #333333;
    line-height: 26px;
    font-size: 16px;
  }
}

.left-chat .chat::after,
.right-chat .chat::after {
  content: "";
  display: block;
  position: absolute;
  top: 10px;
}

.left-chat .chat::after {
  transform: rotate(-45deg);
  border: 5px solid #eaf6f0;
  border-bottom-color: transparent;
  border-right-color: transparent;
  left: -5px;
}

.left-chat .chat {
  font-family: PingFangSC-Regular, PingFang SC;
  font-weight: 400;
  margin: 0 20px;
  color: #333333;
  background: #FFFFFF;
  border-radius: 4px 24px 24px 24px;
}

.left-chat .chat-img,
.right-chat .chat-img {
  width: 35px;
  height: 35px;
  font-size: 35px;
  border-radius: 4px;
  overflow: hidden;
}

.left-chat .chat-img {
  position: absolute;
  top: 0;
  left: 0;
  color: rgb(30, 148, 252);
}

.right-chat .chat-img {
  position: absolute;
  top: 0;
  right: 0;
}

.right-chat .chat {
  // margin-right: 50px;
  float: right;
  background: linear-gradient(270deg, #2567F0 0%, #4C91F9 100%);
  border-radius: 24px 24px 4px 24px;
  font-family: PingFangSC-Regular, PingFang SC;
  font-weight: 400;
  color: #FFFFFF;
  font-size: 16px;
  line-height: 22px;
}

.chat-list .time {
  text-align: center;
}

.chat-list .time a,
.chat-list .right-chat a,
.chat-list .left-chat a {
  position: absolute;
  content: "";
  display: block;
  width: 15px;
  height: 15px;
  background-image: url("../img/msg-del.png");
  background-position: center center;
  background-repeat: no-repeat;
  background-size: contain;
  top: 0;
  cursor: pointer;
}

.chat-list .left-chat a {
  right: -10px;
}

.chat-list .right-chat a,
.chat-list {
  font-size: 13px;
  box-sizing: border-box;
}

.chat-list li {
  margin-bottom: 10px;
}

.right_user_content {
  flex: 1;
}

input {
  height: 30px;
  width: 100px;
  outline: none;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.chat_content textarea {
  height: 50px;
  width: 240px;
  padding: 5px;
}

.label {
  width: 120px;
  text-align: left;
  display: inline-block;
  vertical-align: top;
}

.right_user_content div {
  margin-bottom: 10px;
}

.btn button {
  width: 100px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  cursor: pointer;
}

.left-chat::after {
  display: block;
  content: "";
  clear: both;
  height: auto;
}
</style>
